#include "enigmawindow.h"
#include "ui_enigmawindow.h"
#include <QKeyEvent>
#include <QSet>

EnigmaWindow::EnigmaWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::EnigmaWindow),
    working(false),
    letterPressed(false),
    m_enigmaMachine(new Enigma)
{
    ui->setupUi(this);
    on_resetBtn_clicked();
    ui->statusbar->showMessage(QString("Ready."));
}

EnigmaWindow::~EnigmaWindow()
{
    delete ui;
}

void EnigmaWindow::keyPressEvent(QKeyEvent *env)
{
    if (env->isAutoRepeat() == true) {
        return;
    }
    if ((working == true) && (env->key() >= Qt::Key_A) && (env->key() <= Qt::Key_Z)) {
        char ch = ' ';
        ch = (char)(env->key() & 0x7F);

        if ((ch != ' ') && (letterPressed == false)) {
            letterPressed = true;
            inputText.append(ch);
            ch = m_enigmaMachine->encryptChar(ch);
            highlightLetter(ch);
            outputText.append(ch);
            ui->inputText->setText(inputText);
            ui->outputText->setText(outputText);
            env->accept();
            return;
        }
    }
    QMainWindow::keyPressEvent(env);
}

void EnigmaWindow::keyReleaseEvent(QKeyEvent *env)
{
    if (env->isAutoRepeat() == true) {
        return;
    }

    letterPressed = false;
    clearHighlight();
    QMainWindow::keyReleaseEvent(env);
}

void EnigmaWindow::on_resetBtn_clicked()
{
    inputText.clear();
    outputText.clear();
//    ui->startChars->clear();
//    ui->plugboardPairs->clear();
    ui->inputText->clear();
    ui->outputText->clear();
    ui->startChars->setReadOnly(false);
    ui->plugboardPairs->setReadOnly(false);

    ui->resetBtn->setEnabled(false);
    ui->startBtn->setEnabled(true);
    ui->statusbar->showMessage(QString("Ready."));

    working = false;
}

void EnigmaWindow::on_startBtn_clicked()
{
    if (ui->startChars->text().length() != 3) {
        ui->info_startchars->setText(QString("3 chars needed!"));
        return;
    } else {
        startChars = ui->startChars->text().toUpper();
        ui->info_startchars->clear();
    }
    if ((ui->plugboardPairs->text().length() % 2) == 1) {
        ui->info_plugboard->setText(QString("Invalid PlugBoard!"));
        return;
    } else if (ui->plugboardPairs->text().length() > ROTOR_LETTERS_NUMB) {
        ui->info_plugboard->setText(QString("Too more chars!"));
        return;
    } else {
        plugboardPirs = ui->plugboardPairs->text().toUpper();
        ui->info_plugboard->clear();
    }

    Plugboard *plug = new Plugboard;
    QMap<char,char> pairs;
    for (int i = 0; i < plugboardPirs.length(); i += 2) {
        pairs.insert(plugboardPirs.at(i).toLatin1(), plugboardPirs.at(i+1).toLatin1());
    }
    plug->setPlugboardPairs(pairs);
    m_enigmaMachine->installPlugboard(plug);

    if (ui->reflectorBox->currentIndex() == 0) {
        m_enigmaMachine->installReflector(new ReflectorB);
    } else {
        m_enigmaMachine->installReflector(new ReflectorC);
    }

    switch (ui->rotorsBox1->currentIndex()) {
    case 0:
        m_enigmaMachine->installRotor(0, new RotorI);
        break;
    case 1:
        m_enigmaMachine->installRotor(0, new RotorII);
        break;
    case 2:
        m_enigmaMachine->installRotor(0, new RotorIII);
        break;
    case 3:
        m_enigmaMachine->installRotor(0, new RotorIV);
        break;
    case 4:
        m_enigmaMachine->installRotor(0, new RotorV);
        break;
    case 5:
        m_enigmaMachine->installRotor(0, new RotorVI);
        break;
    case 6:
        m_enigmaMachine->installRotor(0, new RotorVII);
        break;
    case 7:
        m_enigmaMachine->installRotor(0, new RotorVIII);
        break;
    default:
        break;
    }
    switch (ui->rotorsBox2->currentIndex()) {
    case 0:
        m_enigmaMachine->installRotor(1, new RotorI);
        break;
    case 1:
        m_enigmaMachine->installRotor(1, new RotorII);
        break;
    case 2:
        m_enigmaMachine->installRotor(1, new RotorIII);
        break;
    case 3:
        m_enigmaMachine->installRotor(1, new RotorIV);
        break;
    case 4:
        m_enigmaMachine->installRotor(1, new RotorV);
        break;
    case 5:
        m_enigmaMachine->installRotor(1, new RotorVI);
        break;
    case 6:
        m_enigmaMachine->installRotor(1, new RotorVII);
        break;
    case 7:
        m_enigmaMachine->installRotor(1, new RotorVIII);
        break;
    default:
        break;
    }
    switch (ui->rotorsBox3->currentIndex()) {
    case 0:
        m_enigmaMachine->installRotor(2, new RotorI);
        break;
    case 1:
        m_enigmaMachine->installRotor(2, new RotorII);
        break;
    case 2:
        m_enigmaMachine->installRotor(2, new RotorIII);
        break;
    case 3:
        m_enigmaMachine->installRotor(2, new RotorIV);
        break;
    case 4:
        m_enigmaMachine->installRotor(2, new RotorV);
        break;
    case 5:
        m_enigmaMachine->installRotor(2, new RotorVI);
        break;
    case 6:
        m_enigmaMachine->installRotor(2, new RotorVII);
        break;
    case 7:
        m_enigmaMachine->installRotor(2, new RotorVIII);
        break;
    default:
        break;
    }

    m_enigmaMachine->setStartPhase(startChars);

    if (ui->rotateFirst->isChecked()) {
        m_enigmaMachine->enableRotateFirst(true);
    } else {
        m_enigmaMachine->enableRotateFirst(false);
    }

    ui->startChars->setReadOnly(true);
    ui->plugboardPairs->setReadOnly(true);

    ui->resetBtn->setEnabled(true);
    ui->startBtn->setEnabled(false);
    ui->statusbar->showMessage(QString("Working!"));

    working = true;
}

void EnigmaWindow::on_startChars_textChanged(const QString &arg1)
{
    if (arg1.length() != 3) {
        ui->info_startchars->setText(QString("3 chars needed!"));
    } else {
        ui->info_startchars->clear();
    }
    ui->startChars->setText(arg1.toUpper());
}

void EnigmaWindow::on_plugboardPairs_textChanged(const QString &arg1)
{
    if ((arg1.length() % 2) == 1) {
        ui->info_plugboard->setText(QString("Invalid PlugBoard!"));
    } else if (arg1.length() > ROTOR_LETTERS_NUMB) {
        ui->info_plugboard->setText(QString("Too more chars!"));
    } else {
        ui->info_plugboard->clear();
    }
    QString text = arg1.toUpper(), text2;
    QSet<QChar> set(text.begin(), text.end());

    text2.clear();
    foreach (auto ch, set) {
        text2.append(ch);
    }
    if (text.length() != text2.length()) {
        text = text.left(text2.length());
    }

    ui->plugboardPairs->setText(text);
}

void EnigmaWindow::highlightLetter(char ch)
{
    switch (ch) {
    case 'A':
        ui->char_a->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'B':
        ui->char_b->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'C':
        ui->char_c->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'D':
        ui->char_d->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'E':
        ui->char_e->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'F':
        ui->char_f->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'G':
        ui->char_g->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'H':
        ui->char_h->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'I':
        ui->char_i->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'J':
        ui->char_j->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'K':
        ui->char_k->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'L':
        ui->char_l->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'M':
        ui->char_m->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'N':
        ui->char_n->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'O':
        ui->char_o->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'P':
        ui->char_p->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'Q':
        ui->char_q->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'R':
        ui->char_r->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'S':
        ui->char_s->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'T':
        ui->char_t->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'U':
        ui->char_u->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'V':
        ui->char_v->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'W':
        ui->char_w->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'X':
        ui->char_x->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'Y':
        ui->char_y->setStyleSheet(QString("color: #32cd32;"));
        break;
    case 'Z':
        ui->char_z->setStyleSheet(QString("color: #32cd32;"));
        break;
    default:
        break;
    }
}

void EnigmaWindow::clearHighlight()
{
    ui->char_a->setStyleSheet(QString(""));
    ui->char_b->setStyleSheet(QString(""));
    ui->char_c->setStyleSheet(QString(""));
    ui->char_d->setStyleSheet(QString(""));
    ui->char_e->setStyleSheet(QString(""));
    ui->char_f->setStyleSheet(QString(""));
    ui->char_g->setStyleSheet(QString(""));
    ui->char_h->setStyleSheet(QString(""));
    ui->char_i->setStyleSheet(QString(""));
    ui->char_j->setStyleSheet(QString(""));
    ui->char_k->setStyleSheet(QString(""));
    ui->char_l->setStyleSheet(QString(""));
    ui->char_m->setStyleSheet(QString(""));
    ui->char_n->setStyleSheet(QString(""));
    ui->char_o->setStyleSheet(QString(""));
    ui->char_p->setStyleSheet(QString(""));
    ui->char_q->setStyleSheet(QString(""));
    ui->char_r->setStyleSheet(QString(""));
    ui->char_s->setStyleSheet(QString(""));
    ui->char_t->setStyleSheet(QString(""));
    ui->char_u->setStyleSheet(QString(""));
    ui->char_v->setStyleSheet(QString(""));
    ui->char_w->setStyleSheet(QString(""));
    ui->char_x->setStyleSheet(QString(""));
    ui->char_y->setStyleSheet(QString(""));
    ui->char_z->setStyleSheet(QString(""));
}
